#include <iostream>
#include <pthread.h>
#include <string>
#include <cstdio>
#include <unistd.h>
#include <cstring>
#include <memory>
#include <vector>

#include "thread.hpp"
#include "Mutex.hpp"

using namespace std;


// 共享资源,火车票
int tickets = 10000;
// 1、如何看待锁
//    a、锁，本身就是一个共享资源！全局的变量是要被保护的，锁是用来保护全局的资源的，锁本身也是全局资源，锁的安全谁来保护呢？
//    b、pthread_mutex_lock,pthread_mutex_unlock,加锁的过程必须是安全的！加锁的过程其实是原子的！
//    c、如果申请成功，就继续向后执行，如果申请暂时没有成功，执行流会阻塞！
//    d、谁持有锁，谁进入临界区！
// 2、如何理解加锁和解锁的本质 ---- 加锁的过程是原子的
// 3、如果我们想简单的使用，该如何进行封装设计

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; // 锁定义成全局的，不用在使用初始化


// 1、多个执行流进行安全访问的资源 - 临界资源
// 2、我们把多个执行流，访问临界资源的代码 -- 临界区 -- 往往是线程代码中很小的一部分
// 3、想让多个线程串行访问共享资源 -- 互斥
// 4、对一个资源进行访问的时候，要么不做，要么做完 -- 原子性， 不是原子性的情况 -- 
// 一个对资源进行的操作，如果只用一条汇编就能完成  -- 原子性   反之：不是原子的 -- 当前理解，方便描述

// 提出解决方案：加锁！

// 就需要尽可能的让多个线程交叉执行
// 多个线程交叉执行的本质：就是让调度器尽可能的频繁发生线程调度与切换
// 线程一般在什么时候发生切换呢？时间片到了，来了更高优先级的线程，线程等待的时候。
// 线程是在什么时候检测上面的问题呢？从内核态返回用户态的时候，线程要对调度状态进行检测，如果可以，就直接发生线程切换

class ThreadData
{
public:
    ThreadData(const string& threadname,pthread_mutex_t *mutex_p)
    :threadname_(threadname)
    ,mutex_p_(mutex_p)
    {}

    ~ThreadData()
    {}

public:
    std::string threadname_;
    pthread_mutex_t *mutex_p_;
};

void *get_Tickets(void *args)
{
    std::string username = static_cast<const char*>(args);
    // ThreadData *td = static_cast<ThreadData*>(args);

    while(true)
    {
        // 加锁和解锁的过程多个线程串行执行的，程序变慢了
        // 锁只规定互斥访问，没有规定必须让谁优先执行
        // 锁就是真的是让多个执行流进行竞争的结果
       // pthread_mutex_lock(td->mutex_p_);
        // pthread_mutex_lock(&lock);
        {
            LockGuard lockguard(&lock); // RAII风格的加锁
            if (tickets > 0)
            {
                usleep(1234);
                // 值得抢，也就是还存在票
                std::cout << username << " 正在进行抢票" << tickets << endl;
                // std::cout << td->threadname_ << " 正在进行抢票" <<tickets << endl;
                tickets--;
                // pthread_mutex_unlock(td->mutex_p_);
                // pthread_mutex_unlock(&lock);

                // 用这段时间来模拟真实的抢票要花费的时间
                // usleep(1234); // 微秒休眠 1秒 = 1000 毫秒 = 1000 000 微秒 = 10^9 纳秒
            }
            else
            {
                // pthread_mutex_unlock(td->mutex_p_);
                // pthread_mutex_unlock(&lock);
                break;
            }
        }
        // 抢完票就完了吗？ 当然不是
        usleep(1000); // 形成一个订单给用户
    }
    return nullptr;
}

// void *thread_run(void *args)
// {
//     std::string work_type = static_cast<const char*>(args);
//     while(true)
//     {
//         std::cout << "我是一个新线程，我正在做: " << work_type << endl;
//         sleep(1);
//     }
// }




int main()
{
// #define NUM 4
//     pthread_mutex_t lock; // 使用之前加锁
//     pthread_mutex_init(&lock,nullptr); 
//     std::vector<pthread_t> tids(NUM);
//     for(int i = 0; i < NUM; i++)
//     {
//         char buffer[64];
//         snprintf(buffer,sizeof buffer,"thread %d",i + 1);
//         ThreadData* td = new ThreadData(buffer, &lock);
//         pthread_create(&tids[i],nullptr,get_Tickets,td);
//     }

//     for(const auto &tid:tids)
//     {
//         pthread_join(tid,nullptr);
//     }

    pthread_t t1,t2,t3,t4;
    pthread_create(&t1,nullptr,get_Tickets,(void*)"thread 1");
    pthread_create(&t2,nullptr,get_Tickets,(void*)"thread 2");
    pthread_create(&t3,nullptr,get_Tickets,(void*)"thread 3");
    pthread_create(&t4,nullptr,get_Tickets,(void*)"thread 4");

    pthread_join(t1,nullptr);
    pthread_join(t2,nullptr);
    pthread_join(t3,nullptr);
    pthread_join(t4,nullptr);

   // pthread_mutex_destroy(&lock); // 使用完了销毁锁 ,定义成全局的锁就不需要了







    // std::unique_ptr<Thread> thread1(new Thread(get_Tickets,(void*)"user1",1));
    // std::unique_ptr<Thread> thread2(new Thread(get_Tickets,(void*)"user1",2));
    // std::unique_ptr<Thread> thread3(new Thread(get_Tickets,(void*)"user1",3));
    // std::unique_ptr<Thread> thread4(new Thread(get_Tickets,(void*)"user4",4));



    // thread1->join();
    // thread2->join();
    // thread3->join();
    // thread4->join();



    // std::unique_ptr<Thread> thread1(new Thread(thread_run,(void*)"hellothread",1));
    // std::unique_ptr<Thread> thread2(new Thread(thread_run,(void*)"countthread",2));
    // std::unique_ptr<Thread> thread3(new Thread(thread_run,(void*)"logthread",3));

    // thread1->start();
    // thread2->start();
    // thread3->start();

    // thread1->join();
    // thread2->join();
    // thread3->join();

}

// 添加__thread，可以将一个内置类型设置为线程局部存储
//  __thread int g_val = 100;

// 共享资源
// // int g_val = 100;

// string changeId(const pthread_t &thread_id)
// {
//     char tid[64];
//     snprintf(tid,sizeof(tid),"0x%lx",(unsigned long)thread_id);
//     return tid;
// }

// void *start_routine(void *args)
// {
//     string threadname  = static_cast<const char*>(args);
//    // pthread_detach(pthread_self()); // 设置自己为分离状态

//     int cnt = 5;
//     while(true)
//     {
//         //cout << threadname << " running ... " << changeId(pthread_self()) << endl;
//         cout << threadname << " running ... " << changeId(pthread_self()) << "g_val: " << g_val << \
//         " &g_val: " << &g_val << endl;
//         sleep(1);
//         g_val++;
//     }

// }

// int main()
// {
//     pthread_t tid;
//     pthread_create(&tid,nullptr,start_routine,(void*)"thread_one");
//     string main_id = changeId(pthread_self());
//     pthread_detach(tid); // 为了防止出错，不使用主线程sleep,直接在这分离

//    // sleep(2);
//     // cout << "main thread running ... new thread id: " << changeId(tid) << " main thread id: " << main_id<< endl;
//     // int n = pthread_join(tid,nullptr);
//     // cout << "result: " << n << " : " << strerror(n) << endl;

//     while(true)
//     {
//         //cout << "main thread running ... new thread id: " << changeId(tid) << " main thread id: " << main_id<< endl;
//        std:: cout << "main thread running ... new thread id: " << changeId(tid) << " main thread id: " << main_id<< \
//         "g_val: " << g_val <<  " &g_val: " << &g_val << endl;
//         sleep(1);
//     }
//     return 0;
// }


